package de.hm.edu.kinderfinder.communication;

import java.util.Calendar;
import java.util.List;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
import de.hm.edu.kinderfinder.activities.MainMenu;
import de.hm.edu.kinderfinder.activities.MapViewActivity;
import de.hm.edu.kinderfinder.activities.R;
import de.hm.edu.kinderfinder.contentprovider.DataBaseManager;
import de.hm.edu.kinderfinder.pojos.LocationObject;
import de.hm.edu.kinderfinder.pojos.ZoneObject;

/**
 * Diese Klasse ist dafür da eingehende SMS Nachrichten abzufangen, sie zu
 * interpretieren, und zu entscheiden wie sie weiter verarbeitet wird. Sie wurde
 * über das Manifest als Empfänger für SMS Nachrichten registriert.
 * 
 * @author Christopher Samuel Pitter, Lukas Jarosch
 * 
 */
public class ProKiddiesBroadcastreceiver extends BroadcastReceiver {

	// Konstanten zum matchen von SMS Nachrichten.
	private static final CharSequence NEUE_ZONE_SMS = " ist gesetzt auf";
	private static final CharSequence ZONE_ERREICHT_SMS = " erreich";
	private static final CharSequence NEUE_POSITION_SMS = "METER";
	private static final CharSequence ZONE_VERLASSEN_SMS = "verlassen";

	private Context context;
	private Intent intent;
	private NotificationManager mNotificationManager;
	private int NOTIFICATIO_ID;

	public ProKiddiesBroadcastreceiver() {

	}

	/**
	 * Diese Methode wird aufgerufen wenn eine SMS Nachricht eingegangen ist.
	 * 
	 * @param context
	 *            der Anwendung
	 * @param Intent
	 *            mit der beinhaltenden SMS
	 */
	@Override
	public void onReceive(Context context, Intent intent) {

//		CharSequence text = "SMS Received!";
//		int duration = Toast.LENGTH_SHORT;
//
//		Toast toast = Toast.makeText(context, text, duration);
//		toast.show();

		this.context = context;
		this.intent = intent;
		String number;
		String message = null;
		Bundle bundle = intent.getExtras();

		if (bundle != null) { // extrahiert die daten in das PDU (Portocl Data
								// Unit) Format .
			Object[] pdus = (Object[]) bundle.get("pdus");
			for (int i = 0; i < pdus.length; i++) { // erstellt eine SmsMessage
													// String aus den byte
													// daten.
				SmsMessage smsMessage = SmsMessage
						.createFromPdu((byte[]) pdus[i]);
				number = smsMessage.getOriginatingAddress();
				message = smsMessage.getMessageBody().toString();
			}
		}

		// Test SMS Strings f�r das debbugen. Frei anpassbar
		String newZone = "schule3 ist gesetzt auf\nhttp://maps.google.com/maps?q=48.1850,11.5398\n"
				+ "RADIUS ist gesetzt auf\n" + "500ft";

		// F�r testen ob in zone oder nicht: 1800 auf 1810 setzten!
		String locationSMS = "hund ist\nhttp://maps.google.com/maps?q=48.1800,11.5398\n"
				+ " METER von\nHEIM 1025 S\nFLEX 2012 N\n oma 1012 N\n kirche 2212 N";

		String loc2 = "Kein GPS-Signal verfuegbar\n" +
				"Letzte Position\n" +
				"http://maps.google.com/maps?q=GeoCare@48.1636,11.4366&z=12\n" +
				"um\n" +
				"20120104214427\n" +
				"Zelle : 262,001,4328,3fdf";
		
		String loc3 = "Kinder ist\n" +
				"http://maps.google.com/maps?q=GeoCare@48.1810,11.5398&z=12\n" +
				"METER von\n" +
				"HEIM nicht gespeichert\n" +
				"FLEX nicht gespeichert";
		
		String verlassenSMS = "hund hat schule in Richtung NO verlassen.";

		String enteredSMS = "hund hat schule erreicht";

		parseSMS(newZone);
		Toast.makeText(context, "sms", Toast.LENGTH_LONG).show();

	}

	/**
	 * Hier wird erkannt um welchen Typ von GeoCare SMS es sich bei der
	 * Nachricht handelt und je nach dem wird diese dann an die richtige Parser
	 * Methode weitergeleited.
	 * 
	 * @param sms
	 *            die eingangen ist.
	 */
	public void parseSMS(String sms) {
		SmsParser parser = new SmsParser();
		if (sms.contains(NEUE_ZONE_SMS)) {

			processNewZoneAddition(parser.parsNewZone(sms));

		} else if (sms.contains(ZONE_ERREICHT_SMS)) {
			processZoneEntry(parser.parsEntryZone(sms).getZonename());

		} else if (sms.contains(NEUE_POSITION_SMS)) {
			System.out.println("Punkt erhalten");

			LocationObject locationObject = parser.parseNewLocationPoint(sms);

			processIncomingLocation(locationObject);
		} else if (sms.contains(ZONE_VERLASSEN_SMS)) {
			processZoneExit(parser.parsExitZone(sms).getZonename());
		}

	}

	/**
	 * Fügt eine neue Zone in die Datenbank hinzu
	 * 
	 * @param newZone
	 *            die zu hinzuzufügende Zone.
	 */
	private void processNewZoneAddition(ZoneObject newZone) {
		DataBaseManager database = DataBaseManager.getInstance(context);
		database.insertZoneIntoDB(newZone);

	}

	/**
	 * Falls eine Zone verlassen wird, wird überprüft ob dies ein Regelbruch mit
	 * den hinterlegten Daten ergibt. Falls dem so ist wird eine Warnung über
	 * die Notifications ausgegeben.
	 * 
	 * @param name
	 *            Name der Zone die verlassen wurde.
	 */
	private void processZoneExit(String name) {
		DataBaseManager database = DataBaseManager.getInstance(context);
		List<ZoneObject> zones = database.getZonesFromDB();
		for (ZoneObject zone : zones) {
			if (name.equalsIgnoreCase(zone.getZonename())) {
				if (zone.isAlarmIfLeftZoneNow()) {
					startNotification("Zone " + name + " wurde verlassen!!!",
							true);
				} else
					startNotification("Zone " + name + " wurde verlassen.",
							false);
			}
		}
	}

	/**
	 * Hier wird dem Nutzer mitgeteilt das eine neue Zone betreten wurde.
	 * 
	 * @param name
	 *            der Zone die betreten wurde.
	 */
	private void processZoneEntry(String name) {
		startNotification("Zone " + name + " wurde betreten.", false);
	}

	/**
	 * Diese Methode verarbeitet die eingehnde Aktualisierung der aktuellen
	 * Position. Sie ist dafür zustandig das dieser neue Datensatz persitiert
	 * wird. Ebenso prüft sie ob die Anwendung gerade läuft und wenn dem so ist,
	 * wird eine Intent abgesendet das dem Nutzer sofort die neue Position auf
	 * der Karte anzeigt. Zusätzlich wird überprüft ob diese neue Position einen
	 * Regelbruch mit den hinterlegten Zonenregeln darstellt.
	 * 
	 * @param locationObject
	 *            mit den Informationen der neuen Position.
	 */
	private void processIncomingLocation(LocationObject locationObject) {
		// save data
		SharedPreferences prefs = context.getSharedPreferences("Location",
				Context.MODE_PRIVATE);
		prefs.edit().putFloat("latitude", (float) (locationObject.getLatt()))
				.commit();
		prefs.edit().putFloat("longitude", (float) locationObject.getAtt())
				.commit();
		Calendar cal = Calendar.getInstance();
		long time = cal.getTimeInMillis();
		time += 60 * 60 * 1000;
		prefs.edit().putLong("time", time).commit();

		DataBaseManager database = DataBaseManager.getInstance(context);
		List<ZoneObject> zones = database.getZonesFromDB();
		for (ZoneObject zone : zones) {
			if (zone.isAlarmIfLeftZoneNow() && !zone.isInZone(locationObject)) {
				startNotification("Zone " + zone.getZonename()
						+ " wurde verlassen!!", true);
			}
		}

		if (MapViewActivity.isRunning()) {
			sendIntentToMap(locationObject);
		}
	}

	/**
	 * Sendet einen Intent um die Karte mit den neuen Positionsdaten aufzurufen
	 * 
	 * @param locationObject
	 *            aktuelle Positonsdaten.
	 */
	private void sendIntentToMap(LocationObject locationObject) {
		Intent mapIntent = new Intent(context, MapViewActivity.class);
		mapIntent.putExtra("Data", locationObject);
		mapIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(mapIntent);

	}

	/**
	 * Diese Methode erstellt eine Notification die dem User angezeigt werden
	 * kann unabhängig ob die Anwendung läuft.
	 * 
	 * @param notificationText
	 *            der dazustellende Text.
	 * @param isALARM
	 *            ob das nur eine Information oder ein Alarm ist.
	 */
	private void startNotification(String notificationText, boolean isALARM) {
		String ns = Context.NOTIFICATION_SERVICE;
		mNotificationManager = (NotificationManager) this.context
				.getSystemService(ns);
		int icon = R.drawable.map_blue; // icon from resources
		long when = System.currentTimeMillis(); // notification time
		String contentTitle;
		String tickerText;
		if (isALARM) {
			tickerText = "ZONEALARM!!"; // ticker-text
			contentTitle = "Prokiddies ALARM!!!"; // message title
		} else {
			tickerText = "Zonenupdate"; // ticker-text
			contentTitle = "Prokiddies Zonenupdate"; // message title
		}
		Intent notificationIntent = new Intent(this.context, MainMenu.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this.context,
				0, notificationIntent, 0);

		// the next two lines initialize the Notification, using the
		// configurations above
		Notification notification = new Notification(icon, tickerText, when);
		notification.defaults |= Notification.DEFAULT_SOUND;
		notification.setLatestEventInfo(context, contentTitle,
				notificationText, contentIntent);

		NOTIFICATIO_ID = 1;

		mNotificationManager.notify(NOTIFICATIO_ID, notification);
	}

}
